package com.swak.boot.config.vertx;

import java.util.Map;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

import com.swak.annotation.Flux;
import com.swak.security.JWTAuthOptions;
import com.swak.vertx.config.VertxConfig;
import com.swak.vertx.security.SecurityHandler;
import com.swak.vertx.security.SecurityManager;
import com.swak.vertx.security.SecurityService;
import com.swak.vertx.security.handler.Handler;
import com.swak.vertx.security.principal.FluxPrincipalStrategy;
import com.swak.vertx.security.principal.PrincipalStrategy;
import com.swak.vertx.security.principal.TokenPrincipalStrategy;
import com.swak.vertx.transport.VertxProxy;
import com.swak.vertx.transport.server.ReactiveServer;

import io.vertx.ext.web.RoutingContext;

/**
 * 安全配置
 * 
 * @author lifeng
 */
@Configuration
@ConditionalOnClass({ ReactiveServer.class, RoutingContext.class })
@ConditionalOnBean({ SecurityConfigurationSupport.class })
public class SecurityAutoConfiguration {

	/**
	 * Auth 提供器 -- 支持在java 代码中设置密码
	 * 
	 * @param properties
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean(SecurityService.class)
	public SecurityService securityService(VertxProxy proxy, SecurityConfigurationSupport securityConfig) {

		VertxConfig config = proxy.config();

		// jwt 授权配置信息
		JWTAuthOptions options = securityConfig.getJwtAuthOptions();

		// 通过options 的配置方式
		if (options != null) {
			return new SecurityService(options);
		}

		// 默认的配置方式
		return new SecurityService(config.getKeyStorePath(), config.getKeyStorePass(), config.getKeyStoreAlgorithm(),
				config.getTokenExpiresInSeconds());
	}

	/**
	 * 身份管理策略
	 * 
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean(PrincipalStrategy.class)
	public PrincipalStrategy principalStrategy(SecurityService securityService, VertxProxy proxy) {
		VertxConfig config = proxy.config();
		return new TokenPrincipalStrategy(securityService, config.getTokenName());
	}

	/**
	 * 身份管理策略
	 * 
	 * @return
	 */
	@Bean
	@Flux(value = FluxPrincipalStrategy.class)
	public FluxPrincipalStrategy fluxPrincipalStrategy() {
		return new FluxPrincipalStrategy();
	}

	/**
	 * 安全管理
	 * 
	 * @param jwtAuthProvider
	 * @param securityConfig
	 * @return
	 */
	@Bean
	public SecurityManager securityManager(PrincipalStrategy principalStrategy,
			SecurityConfigurationSupport securityConfig) {
		return new SecurityManager(principalStrategy, securityConfig.getRealm());
	}

	/**
	 * 设置安全
	 * 
	 * @return
	 */
	@Bean
	public SecurityHandler securityFilter(SecurityManager securityManager,
			SecurityConfigurationSupport securityConfig) {
		SecurityHandler chainManager = new SecurityHandler(securityManager);

		// 可以配置新的filter
		Map<String, Handler> filters = securityConfig.getHandlers();
		if (!CollectionUtils.isEmpty(filters)) {
			for (Map.Entry<String, Handler> entry : filters.entrySet()) {
				String name = entry.getKey();
				Handler filter = entry.getValue();
				chainManager.addHandler(name, filter);
			}
		}

		// 构建filter chain path - filters
		Map<String, String> chains = securityConfig.getDefinitions();
		if (!CollectionUtils.isEmpty(chains)) {
			for (Map.Entry<String, String> entry : chains.entrySet()) {
				String url = entry.getKey();
				String chainDefinition = entry.getValue();
				chainManager.addDefinition(url, chainDefinition);
			}
		}
		return chainManager;
	}
}